﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Bouyei.SqlProvider;
using Bouyei.SqlProvider.Extensions;
using Bouyei.SqlProvider.Structure;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

namespace SqlProviderTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            string select = Provider.Singleton.Select<Info>()
                .From<Info>()
                .Where(new Info() { name="bouyei",age=12 })
                .SqlString;

            string insert = Provider.Singleton.InsertInto<Info>("tablename",
                new Info() { name = "newbie", age = 13 })
                .SqlString;

            string update = Provider.Singleton.Update<Info>()
                  .Set<Info>(new Info() { name = "openthinking.cn", age = 11 })
                  .Where<Info>(new Info() {name="bouyei",age=2 })
                  .SqlString;

            string delete = Provider.Singleton.Delete<Info>()
                 .From<Info>()
                 .Where<Info>(x => x.name == "bouyei")
                 .SqlString;

            Assert.AreEqual("Select [name] From [Info] Where [name]='abc' ", "", true);
           
        }

        [TestMethod]
        public void TestMethod2()
        {
            Provider<Info> xprovider = new Provider<Info>();
            string xstr = xprovider.Select("name").From("info").OrderBy(new Ordering[] {Ordering.Asc,Ordering.Asc }, "name", "sex").SqlString;
            Assert.AreEqual(xstr, "Select [name] From [info] Group By [name] ", true);
        }

        [TestMethod]
        public void TestMethod3()
        {
            //string str = ResolveExpression<Info>(x => x.name=="1" || x.name=="2" && x.name=="dd");
            List<string> wstr = ResolveExpression<Info>(x => x.name == "1" || x.name == "2" && x.name == "3");

            string pstr = ParameterExpression<Info, string>(x => x.name);
        }

        private List<string> ResolveExpression<T>(System.Linq.Expressions.Expression<Func<T, bool>> exp)
        {
            List<string> expList = new List<string>(8);
            AnalyzeExpressionEx(exp.Body,expList);
            return expList;
        }

        private string ParameterExpression<T,Tsource>(Expression<Func<T,Tsource>> exp)
        {
            if (exp.Body.NodeType == ExpressionType.Parameter) return exp.Name;
            else if (exp.Body.NodeType == ExpressionType.MemberAccess)
            {
                MemberExpression mexp = (MemberExpression)exp.Body;
                if (mexp == null) return string.Empty;
                else return mexp.Member.Name;
            }
            else return string.Empty;
        }

        private Expression AnalyzeExpressionEx(Expression exp, List<string> expList)
        {
            if (exp == null) return null;

            BinaryExpression binEx = exp as BinaryExpression;
            if(binEx!=null) AnalyzeExpressionEx(binEx.Left, expList);

            string leave = string.Empty;
            switch (exp.NodeType)
            {
                case ExpressionType.Parameter:
                    {
                        ParameterExpression param = (ParameterExpression)exp;
                        expList.Add("(" + param.Name);
                        return null;
                    }
                    break;
                case ExpressionType.MemberAccess:
                    {
                        MemberExpression mexp = (MemberExpression)exp;
                        expList.Add("(" +mexp.Member.Name);
                        return null;
                    }
                    break;
                case ExpressionType.Constant:
                    {
                        ConstantExpression cex = (ConstantExpression)exp;
                       expList.Add(cex.Value.ToString()+")");
                       return null;
                    }
                    break;
                default:
                    {
                        if (exp.NodeType == ExpressionType.Equal) expList.Add("=");
                        else if (exp.NodeType == ExpressionType.NotEqual)expList.Add("<>");
                        else if (exp.NodeType == ExpressionType.LessThan) expList.Add("<");
                        else if (exp.NodeType == ExpressionType.LessThanOrEqual)  expList.Add("<=");
                        else if (exp.NodeType == ExpressionType.GreaterThan)expList.Add( ">");
                        else if (exp.NodeType == ExpressionType.GreaterThanOrEqual) expList.Add(">=");
                        else if (exp.NodeType == ExpressionType.AndAlso || exp.NodeType == ExpressionType.And)
                        {
                           expList.Add("and");
                        }
                        else if (exp.NodeType == ExpressionType.OrElse || exp.NodeType == ExpressionType.Or)
                        {
                            expList.Add("or");
                        }
                    }
                    break;
            }

           if(binEx!=null) AnalyzeExpressionEx(binEx.Right, expList);

            return binEx;
        }

        private void InsertList(List<Tuple<string, RL>> list, Tuple<string, RL> tuple)
        {
            //if (tuple.Item2 == RL.Right)
            //{
                list.Add(tuple);
            //}
            //else
            //{
            //    int rootIndex = -1;
            //    for (int i = 0; i < list.Count; ++i)
            //    {
            //        if (list[i].Item2 == RL.Root)
            //        {
            //            rootIndex = i;
            //            break;
            //        }
            //    }
            //    if (rootIndex >= 0)
            //    {
            //        list.Insert(rootIndex, tuple);
            //    }
            //    else
            //    {
            //        list.Add(tuple);
            //    }
            //}
        }

        private bool TreeLeave(List<Tuple<string,RL>> expList,Expression exp,RL rl)
        {
            switch (exp.NodeType)
            {
                case ExpressionType.Parameter:
                    {
                        ParameterExpression param = (ParameterExpression)exp;
                        if (param == null) return false;
                        InsertList(expList, new Tuple<string, RL>(param.Name, rl));
                    }
                    break;
                case ExpressionType.MemberAccess:
                    {
                        MemberExpression mexp = (MemberExpression)exp;
                        if (mexp == null) return false;
                        InsertList(expList, new Tuple<string, RL>(mexp.Member.Name, rl));
                    }
                    break;
                case ExpressionType.Constant:
                    {
                        ConstantExpression cex = (ConstantExpression)exp;
                        if (cex == null) return false;
                        InsertList(expList, new Tuple<string, RL>(cex.Value.ToString(), rl));
                    }
                    break;
            }
            return true;
        }

       public class Info
        {
           public string name { get; set; }

            public int age { get; set; }
        }

        public enum RL
        {
            Root=0,
            left=1,
            Right=2
        }
    }
}
